package cn.com.zsw.gblog.config;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * @author Caizhf
 * @version 1.0
 * @date 2019/10/30 10:05
 * @description 控制器日志切面
 **/
@Aspect
@Slf4j
@Configuration
public class ControllerLogAspect {

    @Pointcut("execution(public * cn.com.zsw.gblog.modules.gblog.controller..*.*(..)))||execution(public * cn.com.zsw.gblog.modules.*.controller..*.*(..)))")
    public void controllerPointCut() {
    }

    @Around("controllerPointCut()")
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        //过滤返回报文日志
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String className = method.getDeclaringClass().getSimpleName();
        String methodName = method.getName();
        //约定俗成，此处swagger ApiOperation接口的value作为方法日志名称
        ApiOperation apiAnnotation = method.getAnnotation(ApiOperation.class);
        //方法作用描述
        String methodTitle = Objects.isNull(apiAnnotation) ? "" : apiAnnotation.value();
        String methodDescription = Objects.isNull(apiAnnotation) ? "" : apiAnnotation.notes();
        Object args[] = joinPoint.getArgs();
        if (null == args || args.length == 0) {
            log.info("方法[{}.{}]开始执行，方法功能[{}]，作用描述[{}] \n入参：null", className, methodName, methodTitle, methodDescription);
        }
        for (Object arg : args) {
            //脱敏
            //arg = SensitiveUtils.desToObj(arg);

//            if (!(arg instanceof HttpServletRequest) && !(arg instanceof HttpServletResponse) && !(arg instanceof BindingResult)) {
            if (!(arg instanceof HttpServletRequest) && !(arg instanceof HttpServletResponse)
                    && !(arg instanceof BindingResult) && !(arg instanceof MultipartFile)) {
                try {
                    log.info("方法[{}.{}]开始执行，方法功能[{}]，作用描述[{}] \n入参：{}",
                            className, methodName, methodTitle, methodDescription,
                            JSONObject.toJSONString(arg, SerializerFeature.WriteMapNullValue, SerializerFeature.PrettyFormat));
                } catch (Exception e) {
                    log.error("请求入参格式化输出错误:{}", e.getMessage());
                }
            }
        }
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long timeConsuming = System.currentTimeMillis() - start;

        log.info("方法[{}.{}]执行结束，耗时:[{}]ms \n回参：{}", className, methodName, timeConsuming,
                JSONObject.toJSONString(result, SerializerFeature.WriteMapNullValue, SerializerFeature.PrettyFormat));
        return result;
    }
}
